package com.trs.util;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;

public class HttpPoolConManager {
	/** 默认创建连接超时时间 */
	private final static int DEFAULT_CONNECTIONTIMEOUT = 30 * 1000;
	/** 默认获取连接超时时间 */
	private final static int DEFAULT_CONNECTIONREQUESTTIMEOUT = 30 * 1000;
	/** 默认数据传输超时时间 */
	private final static int DEFAULT_READIMEOUT = 60 * 10 * 1000;
	/** 默认最大连接数 */
	private final static int DEFAULT_MAX = 1000;
	/** 每个路由最大并发数 */
	private final static int DEFAULT_MAX_PERROUTE = 1000;

	/**
	 * 配置PoolingHttpClientConnectionManager 例如默认每路由最高50并发，具体依据业务来定
	 * 
	 * @return
	 */

	private static PoolingHttpClientConnectionManager poolingHttpClientConnectionManager(HttpClientConfig config) {
		PoolingHttpClientConnectionManager connectionManager;
		try {
			// 在调用SSL之前需要重写验证方法，取消检测SSL
			X509TrustManager trustManager = new X509TrustManager() {
				@Override
				public X509Certificate[] getAcceptedIssuers() {
					return null;
				}

				@Override
				public void checkClientTrusted(X509Certificate[] xcs, String str) {
				}

				@Override
				public void checkServerTrusted(X509Certificate[] xcs, String str) {
				}

			};
			SSLContext ctx = SSLContext.getInstance(SSLConnectionSocketFactory.TLS);
			ctx.init(null, new TrustManager[] { trustManager }, null);
			SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(ctx, NoopHostnameVerifier.INSTANCE);
			Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", socketFactory).build();
			connectionManager = new PoolingHttpClientConnectionManager(registry);
		} catch (Exception e) {
			e.printStackTrace();
			LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory();
			Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslsf).build();
			connectionManager = new PoolingHttpClientConnectionManager(registry);
		}
		connectionManager.setMaxTotal(config.getMaxConnect() > 0 ? config.getMaxConnect() : DEFAULT_MAX);
		connectionManager.setDefaultMaxPerRoute(config.getMaxPerRoute() > 0 ? config.getMaxPerRoute() : DEFAULT_MAX_PERROUTE);
		if (config.getValidateAfterInactivity() > 0) {
			connectionManager.setValidateAfterInactivity(config.getValidateAfterInactivity());
		}
		connectionManager.closeIdleConnections(config.getConnectionRequestTimeout() > 0 ? config.getConnectionRequestTimeout() * 2 : DEFAULT_CONNECTIONREQUESTTIMEOUT * 2, TimeUnit.MILLISECONDS);
		return connectionManager;
	}

	/**
	 * 配置RequestConfig
	 * 
	 * @return
	 */
	private static RequestConfig requestConfig(HttpClientConfig config) {
		return RequestConfig.custom().setConnectionRequestTimeout(config.getConnectionRequestTimeout() > 0 ? config.getConnectionRequestTimeout() : DEFAULT_CONNECTIONREQUESTTIMEOUT).setConnectTimeout(config.getConnectionTimeout() > 0 ? config.getConnectionTimeout() : DEFAULT_CONNECTIONTIMEOUT).setSocketTimeout(config.getSocketTimeout() > 0 ? config.getSocketTimeout() : DEFAULT_READIMEOUT).setRedirectsEnabled(false).build();

	}

	public static CloseableHttpClient getClient(HttpClientConfig config) {
		return HttpClients.custom().setConnectionManager(poolingHttpClientConnectionManager(config)).setKeepAliveStrategy(new HttpKeepAliveStrategy()).setDefaultRequestConfig(requestConfig(config)).build();
	}

	public static CloseableHttpClient getClient() {
		HttpClientConfig config = HttpClientConfig.newBuilder().build();
		return HttpClients.custom().setConnectionManager(poolingHttpClientConnectionManager(config)).setKeepAliveStrategy(new HttpKeepAliveStrategy()).setDefaultRequestConfig(requestConfig(config)).setRetryHandler(httpRequestRetryHandler).build();
	}

	// public class HttpKeepAliveStrategy implements ConnectionKeepAliveStrategy {
	//
	// @Override
	// public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
	// HeaderIterator headerIterator = response.headerIterator(HTTP.CONN_KEEP_ALIVE);
	// HeaderElementIterator iterator = new BasicHeaderElementIterator(headerIterator);
	// while (iterator.hasNext()) {
	// HeaderElement element = iterator.nextElement();
	// String name = element.getName();
	// String value = element.getValue();
	// if (name != null && name.equalsIgnoreCase("timeout")) {
	// return Long.parseLong(value) * 1000;
	// }
	// }
	// System.out.println("没有保持");
	// // 如果没有约定，设置默认时长为60
	// return 60 * 10 * 1000;
	// }
	//
	// }

	// 请求重试处理
	public static HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {
		public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
			if (executionCount >= 2) {// 如果已经重试了5次，就放弃
				return false;
			}
			if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接，那么就重试
				return true;
			}
			if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常
				return false;
			}
			if (exception instanceof InterruptedIOException) {// 超时
				return false;
			}
			if (exception instanceof UnknownHostException) {// 目标服务器不可达
				return false;
			}
			if (exception instanceof ConnectTimeoutException) {// 连接被拒绝
				return false;
			}
			if (exception instanceof SSLException) {// SSL握手异常
				return false;
			}

			HttpClientContext clientContext = HttpClientContext.adapt(context);
			HttpRequest request = clientContext.getRequest();
			// 如果请求是幂等的，就再次尝试
			if (!(request instanceof HttpEntityEnclosingRequest)) {
				return true;
			}
			return false;
		}
	};
}
